﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartRoute.Randomness;
using SmartRoute.Data;

namespace SmartRoute.Analytics
{
    //this class is responsible for searching the solutionspace within n mutations, it will be made a recursive method
    //right now it only goes a depth of 1 mutation
    class LocalSearch
    {
        //runs through the neighboring solutionspace
        public static bool neighborhoodSearch(int depth, Chromosome toExplore, Chromosome best, FitnessTest tester, GenePool poolDynamics, ref double neighborsScorePassingBack)
        {
            
            bool foundBetter = false;
            double bestNeighborScore = -1;
            //test fitness of chromosome we want to test
            double bestScore = tester.testFitness(poolDynamics.convertChromosomeToSolution(toExplore));

            //1. Clone incoming chromosome
            Chromosome exploring = Chromosome.DeepCopy(toExplore);

            //explore current permutation
            foundBetter = LocalIDSearch(exploring, ref best, bestScore, tester, poolDynamics, ref bestNeighborScore, true);

            //2. double loop through stops, performing single switches and setting them back to explore only neighboring permutation space
            for (int i = 0; i < exploring.Stops.Count; i++)
            {

                for (int j = i; j < exploring.Stops.Count; j++)
                {
                    //switch two locations
                    if (i != j)
                    {
                        Stop temp = exploring.Stops[i];
                        exploring.Stops[i] = exploring.Stops[j];
                        exploring.Stops[j] = temp;

                        //search the space
                        foundBetter = LocalIDSearch(exploring, ref best, bestScore, tester, poolDynamics, ref bestNeighborScore, false);

                        //switch back locations
                        temp = exploring.Stops[i];
                        exploring.Stops[i] = exploring.Stops[j];
                        exploring.Stops[j] = temp;
                    }
                }
            }
            neighborsScorePassingBack = bestNeighborScore;
            return foundBetter;
        }

        //checks the neighboring bud id space for a particular permutation
        public static bool LocalIDSearch(Chromosome exploring, ref Chromosome best, double bestScore, FitnessTest tester, GenePool poolDynamics, ref double bestNeighborScorePassedBack, bool currentPermutation)
        {
            bool foundBetter = false;
            double fitnessScoreTemp = -1;
            double bestNeighborScore = -1;

            //test the neighboring combinatoric space around these permutations
            for (int r = 0; r < exploring.Stops.Count; r++)
            {
                //keeps track of the original ID at that location
                int tempID = exploring.BusId[r];

                for (int k = 0; k < exploring.NumBuses; k++)
                {
                    //dont want to check the current setting
                    if (currentPermutation)
                    {
                        //if its the current permutation we dont want to check the actual solution we pass in
                        if (exploring.BusId[r] != k)
                        {
                            exploring.BusId[r] = k;
                            //test the fitness
                            fitnessScoreTemp = tester.testFitness(poolDynamics.convertChromosomeToSolution(exploring));
                            //if better then set as besScore and set a new better neighboring champion
                            //This should not ever return true if the algorithm is doing its job.
                            if (fitnessScoreTemp > bestScore)
                            {
                                best = Chromosome.DeepCopy(exploring);
                                bestScore = fitnessScoreTemp;
                                foundBetter = true;
                            }
                            //keeps track of best neighbor score
                            if (fitnessScoreTemp > bestNeighborScore)
                            {
                                bestNeighborScore = fitnessScoreTemp;
                            }
                        }
                    }
                    else
                    {
                        exploring.BusId[r] = k;
                        //test the fitness
                        fitnessScoreTemp = tester.testFitness(poolDynamics.convertChromosomeToSolution(exploring));
                        if (fitnessScoreTemp > bestScore)
                        {
                            best = Chromosome.DeepCopy(exploring);
                            bestScore = fitnessScoreTemp;
                            foundBetter = true;
                        }
                        if (fitnessScoreTemp > bestNeighborScore)
                        {
                            bestNeighborScore = fitnessScoreTemp;
                        }
                    }

                }

                //resets the bus ID
                exploring.BusId[r] = tempID;
            }
            //set the best neighbor score for the calling method
            bestNeighborScorePassedBack = bestNeighborScore;
            //return a boolean result
            return foundBetter;
        }

    }

}
